--------------Survey Taker-------------
A 4am crack                  2015-12-27
---------------------------------------

Name: Survey Taker
Genre: educational
Year: 1984
Credits:
  Software Design and Development:
    Information Technology Design
    Associates, Inc.
  Producer: Dan Klassen
  Development: Dan Klassen, Kevin
    Dybdal, and Tom Hansen
  Programmer: Kevin Dybdal
  Creative Director: Deborah Kovacs
  Project Manager: Maryellen Kohn
  Senior Project Editor: Jeffrey Siegel
  Project Editor: Andrew Ragan
  Associate Project Editor: Susan
    Edwards
  Art Director: Sandi Young
  Art Production: Dennis Niswander,
    Malcolm Kirton
  Production: Lydia Buechler, Kirin
    Nielsen
Publisher: Scholastic, Inc.
Media: single-sided 5.25-inch floppy
OS: Pronto-DOS
Identical cracks:
  #538 Gertrude's Secrets 1.3
  #514 Bannercatch
  #428 Microzine 16
  #378 Bank Street Storybook
  #363 Moptown Hotel 1.3
  #337 The Adventures of Sinbad
  #325 Fraction Action
  #322 Bumble Plot 1.2
  #321 Gertrude's Puzzles 1.2
  #301 Alice in Wonderland
  #217 The Perfect Score
  #196 Moptown Hotel 1.2
  #192 Magical Myths
  #167 Quations

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  no errors, but copy fills screen with
    garbage and reboots

Copy ][+ nibble editor
  all tracks use standard prologues
  (address: D5 AA 96, data: D5 AA AD)
  but modified epilogues
  (address: FF FF EB, data: FF FF EB)

Disk Fixer
  ["O" -> "Input/Output Control"]
    set Address Epilogue to "FF FF EB"
    set Data Epilogue to "FF FF EB"
  Success! All tracks readable!
  T00 -> looks like a DOS 3.3 RWTS
  T11 -> DOS 3.3 disk catalog
  T01,S07 -> startup program is "HELLO"

Why didn't COPYA work?
  modified epilogue bytes (every track)

Why didn't Locksmith FDB work?
  modified epilogue bytes (every track)

Why didn't my EDD copy work?
  probably a nibble check during boot

Next steps:

  1. AUTOTRACE to capture RWTS
  2. Advanced Demuffin to convert disk
     to standard format
  3. Patch RWTS (if necessary)
  4. Find nibble check and bypass it

                   ~

               Chapter 1
In Which We Attempt To Use The Original
    Disk As A Weapon Against Itself


[S6,D1=original disk]
[S6,D2=blank disk]
[S5,D1=my work disk]

]PR#5
CAPTURING BOOT0
...reboots slot 6...
...reboots slot 5...
SAVING BOOT0
/!\ BOOT0 JUMPS TO $08C0
CAPTURING BOOT1
...reboots slot 6...
...reboots slot 5...
SAVING BOOT1
SAVING RWTS
/!\ NIBBLE CHECK AT $BB00

]BRUN ADVANCED DEMUFFIN 1.5

["5" to switch to slot 5]

["R" to load a new RWTS module]
  --> At $B8, load "RWTS" from drive 1

["6" to switch to slot 6]

["C" to convert disk]

                 --v--

ADVANCED DEMUFFIN 1.5    (C) 1983, 2014
ORIGINAL BY THE STACK    UPDATES BY 4AM
=======PRESS ANY KEY TO CONTINUE=======
TRK:...................................
+.5:
    0123456789ABCDEF0123456789ABCDEF012
SC0:...................................
SC1:...................................
SC2:...................................
SC3:...................................
SC4:...................................
SC5:...................................
SC6:...................................
SC7:...................................
SC8:...................................
SC9:...................................
SCA:...................................
SCB:...................................
SCC:...................................
SCD:...................................
SCE:...................................
SCF:...................................
=======================================
16SC $00,$00-$22,$0F BY1.0 S6,D1->S6,D2

                 --^--

]PR#5
]CATALOG,S6,D2

C1983 DSR^C#254
065 FREE

 A 004 HELLO
 A 006 HELLO2
 A 011 TABLE OF CONTENTS
 B 014 PICDRAWH
 A 006 HELLO2.NEW
 B 033 CREDITS.OVR
 B 033 EXSTARTUP.OVR
 T 001 SIDE
 B 008 SURVEY TAKER.SPC
 B 012 LITTLE APEX
 B 034 LOGO.PIC
 A 004 HELLO2.OLD
 B 091 SURVEY.OVR
 B 033 CREDIT.OVR
 B 041 SAMPLE.OVR
 T 005 SAMPLE.TXT
 B 058 EXGENERIC
 B 042 COMPSTUFF.OVR

[S6,D1=demuffin'd copy]

]PR#6
...fills screen with garbage, reboots
endlessly...

Let's go find that nibble check.

                   ~

               Chapter 2
  In Which We Run Into An Old Friend


]PR#5
]BLOAD BOOT0,A$800
]CALL -151

*801L
.
. all normal until...
.
084A-   4C C0 08    JMP   $08C0

*8C0L

08C0-   8E E9 B7    STX   $B7E9
08C3-   6C FD 08    JMP   ($08FD)

*BLOAD BOOT1,A$2600

*FE89G FE93G     ; disconnect DOS

*B600<2600.2FFFM ; move RWTS into place

*B700L

B700-   20 00 BB    JSR   $BB00

*BB00L

BB00-   A0 00       LDY   #$00
BB02-   B9 00 BB    LDA   $BB00,Y
BB05-   99 00 02    STA   $0200,Y
BB08-   88          DEY
BB09-   D0 F7       BNE   $2B02
BB0B-   60          RTS

*20C<BB0C.BBFFM

*20CL

; this subroutine seeks to track $11
; and sets the reset vector to
; something unfriendly
020C-   20 CF 02    JSR   $02CF
020F-   A9 0A       LDA   #$0A
0211-   85 2A       STA   $2A

; initialize disk motor
; (highly suspicious)
0213-   AE E9 B7    LDX   $B7E9
0216-   BD 89 C0    LDA   $C089,X
0219-   BD 8E C0    LDA   $C08E,X

; set up an address pointer
021C-   A9 C7       LDA   #$C7
021E-   85 48       STA   $48
0220-   A9 02       LDA   #$02
0222-   85 49       STA   $49

; set up the Death Counter
0224-   A9 80       LDA   #$80
0226-   85 29       STA   $29
0228-   C6 29       DEC   $29

; if Death Counter hits 0, jump to
; The Badlands (the point of no return)
022A-   F0 67       BEQ   $0293

; get next address field
022C-   20 44 B9    JSR   $B944

; if that failed for some reason, jump
; to The Badlands
022F-   B0 62       BCS   $0293

; loop until we find sector $0D (in
; zero page $2D after routine at $B944)
0231-   A5 2D       LDA   $2D

; is it the sector we wanted?
0233-   C9 0D       CMP   #$0D

; nope, loop and try again
0235-   D0 F1       BNE   $0228

; look for a $D5 nibble
0237-   A0 00       LDY   #$00
0239-   BD 8C C0    LDA   $C08C,X
023C-   10 FB       BPL   $0239
023E-   88          DEY

; if we don't find one in time, jump to
; The Badlands
023F-   F0 52       BEQ   $0293
0241-   C9 D5       CMP   #$D5
0243-   D0 F4       BNE   $0239

; look for an $E7 nibble
0245-   A0 00       LDY   #$00
0247-   BD 8C C0    LDA   $C08C,X
024A-   10 FB       BPL   $0247
024C-   88          DEY

; if we don't find one in time, jump to
; The Badlands
024D-   F0 44       BEQ   $0293
024F-   C9 E7       CMP   #$E7
0251-   D0 F4       BNE   $0247

; find 2 more $E7 nibbles
0253-   BD 8C C0    LDA   $C08C,X
0256-   10 FB       BPL   $0253
0258-   C9 E7       CMP   #$E7

; Unexpected nibble? The Badlands!
025A-   D0 37       BNE   $0293
025C-   BD 8C C0    LDA   $C08C,X
025F-   10 FB       BPL   $025C
0261-   C9 E7       CMP   #$E7

; Unexpected nibble? Guess where you're
; going!
0263-   D0 2E       BNE   $0293

; kill some time to get out of sync
; with the "proper" start of nibbles
; (see below)
0265-   BD 8D C0    LDA   $C08D,X
0268-   A0 10       LDY   #$10
026A-   24 06       BIT   $06

A short digression here into some super
low-level disk stuff, because this
wasn't low-level enough already...

$E7 $E7 $E7 $E7. What would that nibble
sequence look like on disk? The answer
is, "It depends." $E7 in hexadecimal is
11100111 in binary, so here is the
simplest possible answer:

   |--E7--||--E7--||--E7--||--E7--|
   11100111111001111110011111100111

But wait. Every nibble read from disk
must have its high bit set. In theory,
you could insert one or two "0" bits
after any of those nibbles. (Two is the
maximum, due to hardware limitations.)
These extra "0" bits would be swallowed
by the standard "wait for data latch to
have its high bit set" loop, which you
see over and over in any RWTS code:

  :1   LDA $C08C,X
       BPL :1

Now consider the following bitstream:

  |--E7--| |--E7--|  |--E7--||--E7--|
  11100111011100111001110011111100111
          ^        ^^
       (extra)   (extra)

The first $E7 has one extra "0" bit
after it, and the second $E7 has two
extra "0" bits after it. Totally legal,
works on any Apple II computer and any
floppy drive. A "LDA $C08C,X; BPL" loop
would still interpret this bitstream as
a sequence of four $E7 nibbles. Each of
the extra "0" bits appear after we've
just read a nibble and we're waiting
for the high bit to be set again.

Now, what if we miss the first few bits
of this bitstream, then start looking?
The disk is always spinning, whether
we're reading from it or not. If we
waste too much time doing something
other than reading, we'll literally
miss some bits as the disk spins by.
This is why the timing of low-level
RWTS code is so critical.

Let's say we waste 12 CPU cycles before
we start reading this bitstream. Each
bit takes 4 CPU cycles to go by, so
after 12 cycles, we would have missed
the first 3 bits (marked with an X).

            (normal start)

  |--E7--| |--E7--|  |--E7--||--E7--|
  11100111011100111001110011111100111
  XXX  |--EE--| |--E7--|  |--FC--|

           (delayed start)

Ah! It's interpreted as a completely
different nibble sequence if you delay
just a few CPU cycles before you start
reading. Also note that some of those
"extra" bits are no longer being
ignored; now they're being interpreted
as data, as part of the nibbles that
are being returned to the higher level
code. Meanwhile, other bits that were
part of the $E7 nibbles are now being
swallowed.

Now, let's go back to the first stream,
which had no extra bits between the
nibbles, and see what happens when we
waste those same 12 CPU cycles.

           (normal start)

   |--E7--||--E7--||--E7--||--E7--|
   11100111111001111110011111100111
   XXX  |--FC--||--FC--||--FC--|

          (delayed start)

After skipping the first three bits,
the stream is interpreted as a series
of $FC $FC $FC repeating endlessly --
not $EE $E7 $FC like the other stream.

Here's the kicker: generic bit copiers
didn't preserve these extra "0" bits
between nibbles. By "desynchronizing"
(wasting just the right number of CPU
cycles at just the right time), then
interpreting the bits on the disk in
mid-stream, developers could determine
at runtime whether you had an original
disk. Which is precisely the code we
just saw.

Here is the complete "E7 bitstream,"
annotated to show both the synchronized
and desynchronized nibble sequences.

 |--E7--| |--E7--|  |--E7--||--E7--|
 111001110111001110011100111111001110
 XXX  |--EE--| |--E7--|  |--FC--||--E

 |--E7--|  |--E7--||--E7--| |--E7--|
 111001110011100111111001110111001110
 E--| |--E7--|  |--FC--||--EE--| |--E

 |--E7--||--E7--|
 1110011111100111
 E--| |--FC--|

We now return you to the actual code...

                   ~

               Chapter 3
 In Which We Remove All Traces Of Copy
Protection Using An Automated Tool That
   I Wrote For Just Such An Occasion


Continuing from $026C...

; now start looking for nibbles that
; don't really exist (except they do,
; because we're out of sync and reading
; timing bits as data)
026C-   BD 8C C0    LDA   $C08C,X
026F-   10 FB       BPL   $026C
0271-   88          DEY
0272-   F0 1F       BEQ   $0293  ; fail
0274-   C9 EE       CMP   #$EE
0276-   D0 F4       BNE   $026C

; check for nibble sequence stored
; in reverse order at ($48) [= $02C7]
0278-   A0 07       LDY   #$07
027A-   BD 8C C0    LDA   $C08C,X
027D-   10 FB       BPL   $027A
027F-   D1 48       CMP   ($48),Y
0281-   D0 10       BNE   $0293
0283-   88          DEY
0284-   10 F4       BPL   $027A

; success path falls through to here
0286-   A9 80       LDA   #$80
0288-   8D 4E 9E    STA   $9E4E
028B-   A9 A1       LDA   #$A1
028D-   8D 4F 9E    STA   $9E4F
0290-   4C 4D 9E    JMP   $9E4D

This last section at $0286..$0290 is
interesting. After the nibble check
passes, it replaces two bytes at $9E4E
and $9E4F, then immediately jumps to
$9E4D. That implies that this nibble
check is called from $9E4D via an
unconditional jump (not a JSR). With my
trusty Disk Fixer sector editor, I
searched the disk for "4C 0C 02" and
lo and behold! Track $00, sector $0B,
byte $4D contains a "JMP $020C".

I should be able to change that JMP
back to its original target ($A180) and
bypass the nibble check altogether.

[S6,D1=demuffin'd copy]
[S5,D1=my work disk]

]PR#5
]BRUN PDP

T00,S0B,$4E change 0C02 to 80A1

                   ~

               Epilogue
             On Epilogues


The RWTS is flexible enough to read and
write disks in a standard format, so no
RWTS patches are required. Have I ever
explained how that works? I want to
explain how that works. Here is how
that works.

]PR#5
...
]BLOAD RWTS,A$2800
]CALL -151

*FE89G FE93G     ; disconnect DOS
*B800<2800.2FFFM ; move RWTS into place

*B98BL

; check address epilogue
B98B-   BD 8C C0    LDA   $C08C,X
B98E-   10 FB       BPL   $B98B
B990-   C9 DE       CMP   #$DE
B992-   90 AE       BCC   $B942   <-- !
B994-   EA          NOP
B995-   BD 8C C0    LDA   $C08C,X
B998-   10 FB       BPL   $B995
B99A-   C9 AA       CMP   #$AA
B99C-   90 A4       BCC   $B942   <-- !
B99E-   18          CLC
B99F-   60          RTS

*B92FL

; check data epilogue
B92F-   BD 8C C0    LDA   $C08C,X
B932-   10 FB       BPL   $B92F
B934-   C9 DE       CMP   #$DE
B936-   90 0A       BCC   $B942   <-- !
B938-   EA          NOP
B939-   BD 8C C0    LDA   $C08C,X
B93C-   10 FB       BPL   $B939
B93E-   C9 AA       CMP   #$AA
B940-   B0 5C       BCS   $B99E   <-- !
B942-   38          SEC
B943-   60          RTS

Did you see it? BCC instead of BNE (at
$B992, $B99C, and $B936). Also, BCS
instead of BEQ (at $B940). This is a
very flexible RWTS; it will accept
almost any two epilogue bytes. "DE AA"?
No problem. "FF FF"? Also no problem.
Or literally anything in between.

BCC and BCS operations take exactly the
same amount of time as BNE and BEQ
operations, so the delicate CPU count
is preserved. (Remember, this low-level
RWTS code is sensitive to any timing
changes, since the disk being read is
spinning independently of the CPU
trying to read it as it goes by.)

The write part of the RWTS always uses
the standard "DE AA EB" epilogues. In
fact, the only differences from a disk
that you could create yourself with an
"INIT HELLO" command are those four
branch operations listed above.

The result: a single RWTS that can read
the program disk (which uses "FF FF"
epilogues) and standard disks (with the
"DE AA" epilogues).

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 541
------------------EOF------------------
